home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2001 December
/
pcwk12201b.iso
/
Wersje pelne i specjalne
/
Winamp 2.77 i 3.0beta
/
wasabi-sdk_beta1.exe
/
studio
/
ExampleB
/
exampleBwnd.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2001-10-08
|
20KB
|
544 lines
/*
Nullsoft WASABI Source File License
Copyright 1999-2001 Nullsoft, Inc.
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Brennan Underwood
brennan@nullsoft.com
*/
// ===========================================================================
//
// NULLSOFT WASABI SDK EXAMPLE PROJECTS
//
// File: ExampleBWnd.cpp
//
//!## Purpose: This is the source module that contains the top-level
//!## methods we'll be using for the construction of the ExampleB
//!## window object.
//
// Requires: Please read ExampleBWnd.h first.
//
// Notes: A note on the comments in this document:
// Notes that begin with *** are important notes that everyone
// needs to read. The other comments assist readability or
// explain the thinking behind sections of code which may not
// be immediately obvious to the novice programmer.
//
// Or I'm just typing to hear myself clickyclack.
//
// Always begin with including std.h
#include "../common/std.h"
#include "ExampleB.h"
#include "ExampleBwnd.h"
// To be able to have Example1 as a Child Window
#include "../example1/Example1Wnd.h"
// Child Window Notification Messages
#include "../common/notifmsg.h"
// Core Handle for control of mp3 playback.
#include "../common/corehandle.h"
// Header to allow us to throw a textbar in there.
#include "../common/textbar.h"
// Header for generic guid mangling.
#include "../common/nsguid.h"
// Header for the _ object for language translation.
#include "../common/xlatstr.h"
// Header for ContWnd
#include "../common/contwnd.h"
// Oh, buttons get included up in there somewhere, too....
// ===========================================================================
//
// EXAMPLEB: Static Globals
//
// A simple little static to help us lay out buttons, etc.
static inline int PostIncReturn(int &counter, int amount)
{
// Return the given counter value and increment it by ``amount''
int retval = counter;
counter += amount;
return retval;
}
// ===========================================================================
//
// EXAMPLEB: "ExampleBWnd::ExampleBWnd"
//
// *** We commit the tasks of 1) Instantiation and
// 2) Assembly in the CONSTRUCTOR of the containment
// class. The third primary task to occur before
// normal framelooped behaviour, Initialization,
// occurs AUTOMATICALLY for ALL contained objects by
// the default baseclass onInit() event handler.
//
// *** In addition, it is important to note that any GUI
// objects that take pointers to other gui objects have
// the responsibility for deleting their interred pointrs
// upon the destruction of that object.
//
ExampleBWnd::ExampleBWnd( void ) :
myXMLURLBuffer() // Let our string member fully construct.
{
// Blah blah blah... default initialization values... yadda yadda yadda
myUrlGrab = NULL;
myDownloadState = EXB_DOWNLOAD_READY;
//
// In order to logically segregate the functions, we're
// going to make a new method for our control class that
// we call "createChildWindows" -- here's where we'll setup the
// user interface objects that will exist in our sandbox.
//
// (This lets me move that whole block of code around if I
// screw up and put it in the wrong place, or the API changes)
int myRetval = createChildWindows();
// and yes, we ignore the return code from the fxn.
// what are you going to do about it, in a constructor?
}
// ===========================================================================
//
// EXAMPLEB: "ExampleBWnd::onInit()"
//
// So, okay, the setting of a timer falls neatly under the heading of
// "initialization activities." This is how we latch our initialization
// event and perform our method overrides. STANDARD C++ procedure, of
// course, but I'm gonna be explicit about it, just so there's no problems:
int ExampleBWnd::onInit() {
// By calling our parent class' onInit method, we aught to have all
// of our children properly initialized as well.
int retval = EXAMPLEBWND_PARENT::onInit();
setTimer(EXB_TIMER_ID, EXB_TIMER_DUR);
return retval;
}
// ===========================================================================
//
// EXAMPLEB: "ExampleBWnd::timerCallback(int id)"
//
void ExampleBWnd::timerCallback(int id)
{
// Anyhow, so, we test the ID here to make sure we know
// which timer fell out. Since we only have one timer,
// we didn't HAVE to switch on it, but it helps to setup
// your frameworks like this anyhow. Multiple if-chains
// make things hard to read.
switch (id)
{
case EXB_TIMER_ID:
// Periodically, handle URL downloading.
pollDownloadState();
break;
default:
// If, by some vague stretch of our crazed imaginations,
// someone ELSE in our window derivation chain decided to
// send up a timer, we must then pass it along up the chain.
EXAMPLEBWND_PARENT::timerCallback(id);
// NO, DO NOT QUESTION, JUST DO IT. DO IT! DO IT NOW!!!
//
// grr!
//
break;
};
}
// ===========================================================================
//
// EXAMPLEB: "ExampleBWnd::createChildWindows"
//
int ExampleBWnd::createChildWindows( void )
{
// So? What shall we do today?
// Well, we're inherited from a tabsheet. That means we can make lots of
// little children windows that do their own thing, create them here, add
// them into ourselves, and then have them be properly initialized and
// functional automatically by the system.
//
// Slikschiznitz, eh?
// SO OKAY, now that we know that we are a tabsheet, I guess we start
// stuffing kiddie windows into everything.
// First we'll use the custom-blitting window code we created in Example1. That's
// a good way to start. So, follow along here:
// *** For a child of a tabsheet, the name of the window becomes the name
// listed on the tab. So, the instructions here are:
//
// 1) Instantiate your child window object.
Example1Wnd *myExample1Wnd = new Example1Wnd();
// 2) Give it a name (altho you might have your own custom window
// give itself its own name). For Tabsheet objects, the name
// of the child object becomes the name in the tag.
myExample1Wnd->setName(_("Boring"));
// 3) Add it as a simple child to yourself.
// NOTE: The "Add Child" method for TabSheet allows the specification
// of a "TIP" string.
addChild(myExample1Wnd,_("This is a boring version of ``hello world''"));
// WIP: AFAICT, the tip string is currently ignored. But that won't crush
// us, and it won't stop us from hoping that, one day, all the tip strings
// in all the world can stand together hand in hand in the light of day without
// fear of hatred or reprisals or silly little api bugs that prevent them
// from attaining their full and complete and proper place in our society.
//
// *** Note the _("...") object. The _ object will feed your const string
// through the localization and translation code to allow your strings
// to be translated to other languages.
//
// Here's another copy of the blitter window, in a second tab.
Example1Wnd *myExample1Wnd2 = new Example1Wnd( Example1Wnd::EXCITING );
myExample1Wnd2->setName(_("Exciting"));
addChild(myExample1Wnd2,_("This is a fun version of ``hello world''"));
//
// Now what we're going to do is have an individual method for the instantiation
// and assembly of each tabsheet window. First up will be the example sheet to
// display the proper care and feeding of a gaggle of buttons whose button
// functionality is tied to the core MP3 functionality:
createCoreButtonsSheet();
//
// This one will let you punch in an url to an XML sheet that will download and
// display in a frame window assembly.
createFramesSheet();
// Until we clear up the little retval issue around here (possibly in a later
// version of the SDK), return "0" for failure and "1" for success.
return 1;
}
// ===========================================================================
//
// EXAMPLEB: "ExampleBWnd::createCoreButtonsSheet"
//
int ExampleBWnd::createCoreButtonsSheet() {
// Make some fun buttons that link to the core controls.
// First thing we do is make a container to hold our buttons.
ContWnd * myButtonContainer = new ContWnd();
// Name him, for the tab.
myButtonContainer->setName(_("Buttons"));
// Add him to ourselves to make a new tab sheet.
addChild( myButtonContainer, _("This contains buttons that control core playback.") );
//
// *** Some things to know about ContWnd:
//
// ContWnd is made to contain objects with fixed sizes in a fixed layout.
// The addChild() method explicitly defines and sets the rectangular size
// of the children being added.
//
//
// Now we start making the children objects for the button container.
//
// First thing we want to do is make up an inline counting system
// to allow us to more easily lay out our buttons. The static inline
// method used here is defined at the top of the module.
int y = EXB_TOP_OFFSET; // used by PostIncReturn
// By creating this, I can be lazy and cut and paste my buttons without
// worrying about re-twiddling every pixel position by hand.
// A play button would be nice. So we make a button.
ButtonWnd *play = new ButtonWnd();
// Then we give it some text to display.
play->setButtonText("Play", 16);
// And assign a notification ID to it.
play->setButtonId(EXB_PLAY);
// And assign our object to handle all notifications from this button
play->setNotifyWindow(this);
// And finally add it to the container window.
myButtonContainer->addChild(play, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize*/);
//
// NOTE: The "Notify" stuff is where it all happens, but it's mildly complex.
// checkout ExampleBWnd::childNotify() for where the magic happens.
//
// How about a stop button?
ButtonWnd *stop = new ButtonWnd();
stop->setButtonText(_("Stop"), 16);
stop->setButtonId(EXB_STOP);
stop->setNotifyWindow(this);
myButtonContainer->addChild(stop, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// How about a pause button?
ButtonWnd *pause = new ButtonWnd();
pause->setButtonText(_("Pause"), 16);
pause->setButtonId(EXB_PAUSE);
pause->setNotifyWindow(this);
myButtonContainer->addChild(pause, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// Space down by 2 yspacers.
PostIncReturn(y, EXB_BUTTON_SPACER + EXB_BUTTON_SPACER);
// "Previous" button....
ButtonWnd *prev = new ButtonWnd();
prev->setButtonText(_("Previous"), 16);
prev->setButtonId(EXB_PREVIOUS);
prev->setNotifyWindow(this);
myButtonContainer->addChild(prev, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// "Next" button....
ButtonWnd *next = new ButtonWnd();
next->setButtonText(_("Next"), 16);
next->setButtonId(EXB_NEXT);
next->setNotifyWindow(this);
myButtonContainer->addChild(next, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// Space down by 4 yspacers.
PostIncReturn(y, EXB_BUTTON_SPACER * 4);
// And create some text items.
TextBar *textbar = new TextBar();
textbar->setName(_("This is my text bar to say that the next text bars are my guid."));
myButtonContainer->addChild(textbar, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// Want to display your GUID?
TextBar *guidbar = new TextBar();
char text[200];
// I'm being a dick and connecting to my guid as a global variable.
// that's lame and sloppy programming, kids. never do that. :)
extern GUID exb_guid;
guidbar->setName(nsGUID::toChar(exb_guid, text));
// Oh yah, and DON'T be a goddamn hypocrite, either!
// (inspect the "nsGUID::toChar" function, however)
myButtonContainer->addChild(guidbar, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// Want to test that guids are being properly translated?
GUID testGUID = nsGUID::fromChar(text);
// Want to display your crosstranslated GUID?
TextBar *testguidbar = new TextBar();
char testtext[200];
testguidbar->setName(nsGUID::toChar(testGUID, testtext));
myButtonContainer->addChild(testguidbar, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// And one more text item for good measure, eh?
TextBar *textbar2 = new TextBar();
textbar2->setName(_("Are they equal?"));
myButtonContainer->addChild(textbar2, EXB_LEFT_OFFSET,
PostIncReturn(y, EXB_BUTTON_HEIGHT + EXB_BUTTON_SPACER),
EXB_BUTTON_WIDTH * 6, EXB_BUTTON_HEIGHT, 0/*"Invalidate on Resize"*/);
// For the nonce, return codes from and to the API should
// return "0" for failure and "1" for success.
return 1;
}
// ===========================================================================
//
// EXAMPLEB: "ExampleBWnd::childNotify"
//
//
// Okay, so, we're going to use our single derived object to properly dispatch
// all the messaging from our children of myriad diversity.
//
// This means I need to tell you about all the useful notification
// messages that you might encounter in your day to day life with
// our lovely little SDK:
//
// *** BUTTON Notifications:
//
// SO, firstly, we have buttons. Stock ButtonWnd objects will send the
// following Notification messages:
//
// CHILD_NOTIFY_LEFTPUSH
// CHILD_NOTIFY_RIGHTPUSH
// CHILD_NOTIFY_LEFTDOUBLECLICK
// CHILD_NOTIFY_RIGHTDOUBLECLICK
//
// And the id that you assign to the button is sent as param1.
//
int ExampleBWnd::childNotify (RootWnd *which, int msg, int param1, int param2) {
# if 1 // WIP
char text[200];
wsprintf(text,"Incoming rootWnd-childNotify: ptr:0x%08X msg:0x%03X p1:0x%08X p2:0x%08X \n",
which, msg, param1, param2);
OutputDebugString(text);
# endif // WIP
//
// For the nonce, we're going to ignore the pointer to the object who is
// sending the notification event. Pointers are icky, smelly, and if you
// touch them, you'll have to wash your hands with an aerosol oven cleaner
// for a week just to make sure you're not accidentally besmirched.
//
// OBVIOUSLY, if any of the objects you're using require an acknowledgement
// or any other method to be called on them, you'll want to implement a
// schema for your code that keeps the "which" pointer around. But we're
// not going to bother being that complicated here, kiddies.
//
// Uncle mig's got a deadline, you know.
//
handleChildNotify(msg, param1, param2);
return EXAMPLEBWND_PARENT::childNotify(which, msg, param1, param2);
}
// ===========================================================================
//
// EXAMPLEB: "ExampleBWnd::handleChildNotify"
//
// Just to show off message handling without pointers.
//
int ExampleBWnd::handleChildNotify (int msg, int param1, int param2) {
//
// We're all familiar with nested switch for event handling.
// There's nothing scary to be seen, here.
switch(msg)
{
// Messages from our buttons being pushed.
case CHILD_NOTIFY_LEFTPUSH :
case CHILD_NOTIFY_RIGHTPUSH :
case CHILD_NOTIFY_LEFTDOUBLECLICK :
case CHILD_NOTIFY_RIGHTDOUBLECLICK :
{
//
// So, now, what we're going to do here is if ANY of those
// messages came in, we just check which object ID shot that
// message out in order to know what to do with it.
//
int ButtonID = param1; // Just a clarification assignment.
// Switch on the ID to call the core handle.
switch(ButtonID)
{
case EXB_PREVIOUS:
{
OutputDebugString(_("Button pushed corresponds to EXB_PREVIOUS ButtonID\n"));
CoreHandle newHandle;
newHandle.prev();
break;
}
case EXB_PLAY:
{
OutputDebugString(_("Button pushed corresponds to EXB_PLAY ButtonID\n"));
CoreHandle newHandle;
newHandle.play();
break;
}
case EXB_PAUSE:
{
OutputDebugString(_("Button pushed corresponds to EXB_PAUSE ButtonID\n"));
CoreHandle newHandle;
newHandle.pause();
break;
}
case EXB_STOP:
{
OutputDebugString(_("Button pushed corresponds to EXB_STOP ButtonID\n"));
CoreHandle newHandle;
newHandle.stop();
break;
}
case EXB_NEXT:
{
OutputDebugString(_("Button pushed corresponds to EXB_NEXT ButtonID\n"));
CoreHandle newHandle;
newHandle.next();
break;
}
// Ah! THIS button is created and used on the "Frames" sheet, in the other module.
case EXB_XML_GO:
{
OutputDebugString(_("Button pushed corresponds to EXB_XML_GO ButtonID\n"));
// And you'll find this method there, as well.
startURLDownload();
break;
}
default:
// Hrrmph.
return 0;
}
}
break;
default:
// Hrrmph.
return 0;
}
//
// Yawn. Do I care about my error condition, here?
//
// Oh PROBABLY.
//
// SOMEWHERE.
//
// Maybe in North Dakota or something.
//
// So, if you're a developer, and you're IN North Dakota, well,
// I feel so sorry for you that I'd suggest immediately changing
// the return value here from a 1 to a 0. It won't make a big
// difference in the functionality here, but it will help bring
// unto you that most invaluable of gifts:
//
// Peace of mind.
//
// See, aren't I a great pal?
return 1;
}